open Ast_TablePro

module NameMap = Map.Make(struct
  type t = string
  let compare x y = Pervasives.compare x y
end)

let rec string_of_expr = function
    Literal(l) -> string_of_float l
  | IntLiteral(l) -> string_of_int l
  | StrLiteral(s) -> s
  | Id(s) -> s
  | IndexSize(s) -> s
  | Binop(e1, o, e2) -> string_of_expr e1 ^ " " ^(match o with Add -> " + " ^ string_of_expr e2 | Sub -> "-"  ^ string_of_expr e2| Mult -> "*" ^ string_of_expr e2 | Div -> "/" ^ string_of_expr e2 
  | Equality ->  " == " ^ string_of_expr e2 | And -> " Log && " ^ string_of_expr e2 | Less -> "<"^ string_of_expr e2  |  Greater -> ">" ^ string_of_expr e2 | Or -> " Log Or "^ string_of_expr e2 )
  | Assign(v, e) -> v ^ " = " ^ string_of_expr e
  | IndexAsn ( s, e1 ,e2) -> s ^ "[" ^ string_of_expr e1  ^ " ] = " ^ string_of_expr e2
  | Call(f, el) -> f ^ "(" ^ String.concat ", " (List.map string_of_expr el) ^ ")"
  | Index(s, e) -> s ^ "[" ^ string_of_expr e ^ "]"
  | IndexRange(s, i, j, op, e) -> s ^ "[" ^ string_of_expr i ^ "-" ^ string_of_expr j ^ "]" ^ 
  			(match op with Add -> " + " ^ string_of_expr e | Sub -> "-"  ^ string_of_expr e
  			| Mult -> "*" ^ string_of_expr e | Div -> "/" ^ string_of_expr e  | _ ->"Op not supported")
  
  

let rec string_of_formal  = function
Sarg (s1 , s2) -> s1 ^" * "^ s2  
| Carg (s1 , s2, s3, s4) -> s1 ^" * "^ s2  ^  s3 ^" * "^ s4  
	 
let rec string_of_formals list = "" ^ String.concat "" (List.map string_of_formal list)


let rec string_of_stmt = function
    SDeclstmnt (s1 , s2) -> "Declared " ^ s1 ^ s2
  |  CDeclstmnt (s1 , s2, s3, s4) -> "Declared " ^ s1 ^ s2 ^ s3 ^ s4
  |  CNumdeclAsnstmnt ( s1, s2, s3, s4, l) -> "Declared " ^ s1 ^ s2 ^ s3 ^ s4
  |  CStrdeclAsnstmnt ( s1, s2, s3, s4, l) -> "Declared " ^ s1 ^ s2 ^ s3 ^ s4
  |  Block(stmts) -> "{\n" ^ String.concat "" (List.map string_of_stmt stmts) ^ "}\n"
  | Stmnt(expr) -> string_of_expr expr ^ ";\n";
  | Return(s) -> "return " ^ s ^ "\n";
  | If(e, slist1 , slist2) -> "if (" ^ String.concat "" (List.map string_of_stmt slist1) ^ String.concat "" (List.map string_of_stmt slist2)  
  | Loop(e1, slist) -> "loop " ^ string_of_expr e1  ^ " Loop begin " ^ String.concat "" (List.map string_of_stmt slist)  ^ " Loop end "
  | GenerateStmnt(slist) -> "Generate table for " ^ (List.fold_left (fun s1 s2 -> s1 ^ s2)  ""  slist)
  | Func_decl(s1, list1 , s2, list2) -> string_of_fdecl s1 list1 s2 list2

	and 
	 string_of_fdecl  s1  list1  s2 list2 =
	  s1 ^ "(" ^ string_of_formals list1^ ")" ^ "\n{\n" ^
	  String.concat "" (List.map string_of_stmt list2) ^  "}\n"	 
	


let string_of_program (slist) = print_string "in printer\n";
  String.concat "" (List.map string_of_stmt slist) ^ "\n"


let rec string_of_col_type t =
	(match t with Num -> " num " 
	| Str -> "str"  
	| _ -> raise (Failure ("unsupported column type " )))
	
let string_of_Col c = "Col Of"^ c.colName^(string_of_col_type c.colContentType)  		


let rec string_of_vdecl_type t =
	(match t with Num -> " num " 
	| Str -> "str"  | Col  c -> string_of_Col c)
 



let rec string_of_vdecl  s1  t  =
	      	  " Name: " ^ s1 ^ " Type: " ^ (string_of_vdecl_type t)  

let vdecl_from_str s =
	(match s with "num:" -> Num 
		    | "str:"-> Str  
		    | _     -> raise (Failure ("undefined type " ^ s)))

let string_of_retval retvalue =
	(match retvalue with 
	            F f -> ("float of " ^ string_of_float f )
		  | S s -> ("string of" ^ s)  
		  | _-> "A list of values")



let rec print_locals locals  = 
   let f k e =  print_endline ("Key: " ^ k ^ "Vdecl: "^ (string_of_vdecl e.vname e.vtype ) ^ string_of_retval e.vVal)
      in 
 	print_endline "Locals"; NameMap.iter f locals 
 
(* let print_globals (globals) =
    let f k e =  print_endline ("Key: " ^ k ^ "Type: "^ e)
       in 
 	print_endline "globals"; NameMap.iter f globals *)
 	
let rec print_globals globals  = 
   let f k e =  print_endline ("Key: " ^ k ^ "Vdecl: "^ (string_of_vdecl e.vname e.vtype ))
      in 
 	print_endline "Globals"; NameMap.iter f globals  	
 

let rec string_of_fdecl  s1  list1  s2 list2  =
	      	  " Name: "^ s1 ^ "(" ^ string_of_formals list1^ ")" ^ "\n{\n" ^
	      	  String.concat "" (List.map string_of_stmt list2) ^  "}\n " 

let rec string_of_function  k e =
		let a = string_of_fdecl e.fname e.formals (string_of_vdecl_type e.retType) e.body
		in
 	   		k ^ a
 	   
  let print_functions (functions) =
     let f k e =  print_endline (string_of_function k e)
       	in 
		NameMap.iter  f functions


let print_final_table lists = print_string "Rajat is doign this" ; 
				true;